// Core Contoller
// (c) jimon game studio

#include "jeEngineController.h"

// singletons
#include "jeMemory.h"
#include "IProfiler.h"
#include "ITimer.h"
#include "ILogManager.h"
#include "IVariables.h"
#include "ISystem.h"
#include "IFpsCounter.h"
#include "IFileSystem.h"
#include "IJEDManager.h"
#include "ISoundManager.h"
#include "IImageLoader.h"
#include "IScriptManager.h"
#include "IResourceManager.h"
#include "IFontManager.h"
#include "IMeshLoader.h"
//
// resources
#include "jeImageResource.h"
#include "jeSoundResource.h"
#include "jeScriptResource.h"
#include "jeShaderMaterialResource.h"
#include "jeMaterialResource.h"
#include "jeMeshResource.h"
#include "jeFontResource.h"

// other
#include "jeScriptInterface.h"

namespace je
{
	namespace core
	{
		#define JE_GRAB_FEATURE( __namespace, __name )\
			if( __namespace::Get##__name())\
				__namespace::Get##__name()->Grab();\
			else\
				__namespace::CreateSingleton##__name();

		#define JE_DROP_FEATURE( __namespace,__name )\
			if(__namespace::Get##__name()){\
				u1 ret = __namespace::Get##__name()->Drop();\
				JEASSERT(ret)}

		#define REGRESOURCE(__type)\
			media::je##__type##ResourceFactory * __type##ResourceFactory = NULL;\
			JENEW( __type##ResourceFactory ,media::je##__type##ResourceFactory)\
			media::GetResourceManager()->RegisterResourceFactory( __type##ResourceFactory );\
			__type##ResourceFactory->Drop();

		typedef jeDynamicArray<app::IPerspective*> PerspectiveDynamicArrayType;
		PerspectiveDynamicArrayType PerspectiveArray;

		u1 EngineRunning;

		//! Init Engine
		void JE_ENGINE_FUNCTION_CALL InitEngine()
		{
			MemoryGrab();

			JE_GRAB_FEATURE(core,Timer)
			JE_GRAB_FEATURE(core,Profiler)
			JE_GRAB_FEATURE(core,LogManager)

			JELOG_SHORT("-------------------------")
			JELOG_SHORT(jeStringc("Enesea v")+jeStringc(JE_ENGINE_VERSION))
			JELOG_SHORT("(c) jimon game studio")
			JELOG_SHORT("-------------------------")

			JE_GRAB_FEATURE(core,Variables)

			JESETVARIABLE("Enesea_WorkingDirectory","")
			JESETVARIABLE("Device_DefaultWindowTitle","Enesea Application")
			JESETVARIABLE("OpenGL_Support_VBO",1)
			JESETVARIABLE("OpenGL_Support_VSync",1)
			JESETVARIABLE("OpenGL_Support_DrawRange",1)
			JESETVARIABLE("OpenGL_Support_MultiTextures",1)
			JESETVARIABLE("OpenGL_Support_AATextures",1)
			JESETVARIABLE("OpenGL_Support_S3TC",1)
			JESETVARIABLE("OpenGL_Support_FBO",1)
			JESETVARIABLE("OpenGL_Support_GLSL",1)
			JESETVARIABLE("OpenGL_Support_GLSL_Version",(s32)150)
			JESETVARIABLE("OpenGL_ForwardContext",1)
			JESETVARIABLE("OpenGL_Driver_Mode",32)
			JESETVARIABLE("OpenGL_LogVersion",1)
			JESETVARIABLE("OpenGL_LogExtensions",0)
			JESETVARIABLE("Squall_FreeAllOnExit",0)
			JESETVARIABLE("AngelScript_TimeOut",10.0f)
			JESETVARIABLE("SceneManager_DSCompositor_AA",1)
			JESETVARIABLE("SceneManager_DSCompositor_Lights_PerPass",4)
			JESETVARIABLE("SceneManager_DSCompositor_AA_Samples",-1)
			JESETVARIABLE("SceneManager_ForwardCompositor_Lights_PerPass",4)
			JESETVARIABLE("SceneManager_EnableSufracesDefaultMaterial",1)
			JESETVARIABLE("SceneManager_SufracesDefaultMaterialName","Default")
			JESETVARIABLE("SceneManager_SufracesDefaultUseUniqueMaterial",0)
			JESETVARIABLE("SceneManager_SufracesDefaultUseUniqueTexture",0)
			JESETVARIABLE("SceneManager_SufracesDefaultUseUniqueShader",0)

			JE_GRAB_FEATURE(core,System)
			JE_GRAB_FEATURE(core,FpsCounter)
			JE_GRAB_FEATURE(core,FileSystem)
			JE_GRAB_FEATURE(core,JEDManager)
			JE_GRAB_FEATURE(core,ScriptManager)
			#ifdef JE_SOUND
			JE_GRAB_FEATURE(sound,SoundManager)
			#endif
			JE_GRAB_FEATURE(video,ImageLoader)
			JE_GRAB_FEATURE(video,FontManager)
			JE_GRAB_FEATURE(scene,MeshLoader)
			JE_GRAB_FEATURE(media,ResourceManager)

			RegisterScriptInterface();

			REGRESOURCE(Image)
			REGRESOURCE(Script)
			REGRESOURCE(ShaderMaterial)
			REGRESOURCE(Material)
			REGRESOURCE(Mesh)
			REGRESOURCE(Font)
			#ifdef JE_SOUND
			REGRESOURCE(Sound)
			#endif

			EngineRunning = true;

			JELOG("Core Started")
		}

		//! DeInit Engine
		void JE_ENGINE_FUNCTION_CALL DeInitEngine()
		{
			JELOG("Core Stoped")

			PerspectiveArray.Clear();

			JE_DROP_FEATURE(media,ResourceManager)
			JE_DROP_FEATURE(scene,MeshLoader)
			JE_DROP_FEATURE(video,FontManager)
			JE_DROP_FEATURE(video,ImageLoader)
			#ifdef JE_SOUND
			JE_DROP_FEATURE(sound,SoundManager)
			#endif
			JE_DROP_FEATURE(core,ScriptManager)
			JE_DROP_FEATURE(core,JEDManager)
			JE_DROP_FEATURE(core,FileSystem)
			JE_DROP_FEATURE(core,FpsCounter)
			JE_DROP_FEATURE(core,System)
			JE_DROP_FEATURE(core,Variables)

			JELOG_SHORT("-------------------------")
			JELOG_SHORT("Stop Engine")
			JELOG_SHORT("-------------------------")

			JE_DROP_FEATURE(core,LogManager)
			JE_DROP_FEATURE(core,Profiler)
			JE_DROP_FEATURE(core,Timer)

			MemoryDrop();

			EngineRunning = false;
		}

		//! Engine Tick
		void JE_ENGINE_FUNCTION_CALL EngineTick()
		{
			GetFpsCounter()->LoopTick();
			media::GetResourceManager()->GarbageCollector();
			GetScriptManager()->GarbageCollector();
			GetProfiler()->LoopTick();
		}

		//! Stop Engine
		void JE_ENGINE_FUNCTION_CALL StopEngine()
		{
			EngineRunning = false;
		}

		//! Run Engine
		void JE_ENGINE_FUNCTION_CALL RunEngine(app::IApplication * App)
		{
			App->SetRun(true);

			JELOG("Enter Main Cycle")

			while(App->IsRun() && EngineRunning)
			{
				JEP_BEG("Application Update")
				App->BeginUpdate();
				for(u32 i=0;i<PerspectiveArray.GetSize();i++)
					if(PerspectiveArray[i]->IsRun())
						PerspectiveArray[i]->OnUpdate();
				App->EndUpdate();
				JEP_END("Application Update")

				JEP_BEG("Application Render")
				App->BeginRender();
				for(u32 i=0;i<PerspectiveArray.GetSize();i++)
					if(PerspectiveArray[i]->IsRun())
						PerspectiveArray[i]->OnRender();
				App->EndRender();
				JEP_END("Application Render")

				JEP_BEG("Application Tick")
				App->Tick();
				for(u32 i=0;i<PerspectiveArray.GetSize();i++)
					if(PerspectiveArray[i]->IsRun())
						PerspectiveArray[i]->Tick();
				JEP_END("Application Tick")

				JEP_BEG("Engine Tick")
				EngineTick();
				JEP_END("Engine Tick")
			}

			JELOG("Exit Main Cycle")
		}

		//! Register Perspective
		void JE_ENGINE_FUNCTION_CALL RegisterPerspective(app::IPerspective * Perspective)
		{
			Perspective->Grab();
			PerspectiveArray.InsertElement(Perspective);
		}

		//! UnRegister Perspective
		void JE_ENGINE_FUNCTION_CALL UnRegisterPerspective(app::IPerspective * Perspective)
		{
			u32 Index = 0;
			if(PerspectiveArray.LinearSearch(Perspective,Index))
				PerspectiveArray.EraseElement(Index);
			Perspective->Drop();
		}

		//! UnRegister All Perspectives
		void JE_ENGINE_FUNCTION_CALL UnRegisterAllPerspectives()
		{
			for(u32 i=0;i<PerspectiveArray.GetSize();i++)
				PerspectiveArray[i]->Drop();
			PerspectiveArray.Clear();
		}

		//! Set Up Perspective
		void JE_ENGINE_FUNCTION_CALL SetUpPerspective(app::IPerspective * Perspective)
		{
			u32 Index = 0;
			if(PerspectiveArray.LinearSearch(Perspective,Index) && (Index > 0))
				PerspectiveArray.Swap(Index-1,Index);
		}

		//! Set Down Perspective
		void JE_ENGINE_FUNCTION_CALL SetDownPerspective(app::IPerspective * Perspective)
		{
			u32 Index = 0;
			if(PerspectiveArray.LinearSearch(Perspective,Index) && (Index<(PerspectiveArray.GetSize()-1)))
				PerspectiveArray.Swap(Index+1,Index);
		}
	}
}
